﻿using Common;
using MyCanFD;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace T68Control.T68
{
    /// <summary>
    /// 控制板测试
    /// </summary>
    internal class T68PBControl
    {
        private CanFdManager canFd;
        private List<Thread> backgroundThreads = new List<Thread>();
        private int counter = 0; // 计数器
        private Timer timer;     // 定时器

        /// <summary>
        /// 100ms发送周期
        /// </summary>
        private string id0x3BBMessage = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00";

        /// <summary>
        /// 20ms发送周期
        /// </summary>
        private string id0x268Message = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";

        /// <summary>
        /// 10ms发送周期
        /// </summary>
        private string id0x160Message = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";

        /// <summary>
        /// 40ms发送周期
        /// </summary>
        private string id0x361Message = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00";

        /// <summary>
        /// 40ms发送周期
        /// </summary>
        private byte[] id0x17EMessage = new byte[64];

        private byte id0x17ECountCH1 = 0;
        private byte id0x17ECountCH2 = 0;
        private bool isChargingCH1 = false;
        private bool isChargingCH2 = false;
        private bool isStrongMode = false;
        private bool isInit = false;

        /// <summary>
        /// 生成校验码
        /// </summary>
        /// <param name="data"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        private static ushort CRC16_CCITT(byte[] data, int length)
        {
            const ushort CRC_INIT = 0xFFFF;
            const ushort CRC_POLY = 0x1021;
            ushort crc = CRC_INIT;

            foreach (byte b in data)
            {
                crc ^= (ushort)(b << 8);
                for (int i = 0; i < 8; i++)
                    crc = (crc & 0x8000) != 0 ? (ushort)((crc << 1) ^ CRC_POLY) : (ushort)(crc << 1);
            }
            return crc;
        }

        /// <summary>
        /// 初始化设备
        /// </summary>
        public void Init()
        {
            canFd = new CanFdManager();
            canFd.Baud_Domain = 500000;
            canFd.Baud_Data = 2000000;
            canFd.QueueSize = 1024;
            canFd.OpenDevice();
            canFd.InitializeAndStart();

            isInit = true;
            counter = 0;
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            Thread thread = new Thread(() =>
            {
                while (isInit)
                {
                    while (stopwatch.ElapsedMilliseconds < 10)
                    {
                    }
                    stopwatch.Restart();
                    TimerCallback();
                }
            });
            thread.Priority = ThreadPriority.Highest;
            thread.IsBackground = true;
            thread.Start();
        }

        private void TimerCallback()
        {
            if (isChargingCH1)
            {
                canFd.SendMessage(0x160, id0x160Message, 0);
                if (counter % 2 == 0)
                {
                    canFd.SendMessage(0x268, id0x268Message, 0);
                }
                if (counter % 4 == 0)
                {
                    canFd.SendMessage(0x361, id0x361Message, 0);

                    {
                        id0x17EMessage[2] = id0x17ECountCH1;
                        var crc = CRC16_CCITT(id0x17EMessage.Skip(2).ToArray(), 54);
                        id0x17EMessage[0] = (byte)(crc & 0xff);
                        id0x17EMessage[1] = (byte)(crc >> 8 & 0xff);
                        canFd.SendMessage(0x17E, id0x17EMessage, 0);
                        id0x17ECountCH1++;

                        if (id0x17ECountCH1 > 255)
                        {
                            id0x17ECountCH1 = 0;
                        }
                    }
                }
                if (counter % 10 == 0)
                {
                    canFd.SendMessage(0x3BB, id0x3BBMessage, 0);
                }
                if (isStrongMode)
                {
                    if (counter % 20 == 0)
                    {
                        canFd.SendMessage(0x63E, "02 3E 00 00 00 00 00 00", 0);
                    }
                }
            }

            if (isChargingCH2)
            {
                canFd.SendMessage(0x160, id0x160Message, 1);
                if (counter % 2 == 0)
                {
                    canFd.SendMessage(0x268, id0x268Message, 1);
                }
                if (counter % 4 == 0)
                {
                    canFd.SendMessage(0x361, id0x361Message, 1);

                    {
                        id0x17EMessage[2] = id0x17ECountCH2;
                        var crc = CRC16_CCITT(id0x17EMessage.Skip(2).ToArray(), 54);
                        id0x17EMessage[0] = (byte)(crc & 0xff);
                        id0x17EMessage[1] = (byte)(crc >> 8 & 0xff);
                        canFd.SendMessage(0x17E, id0x17EMessage, 1);
                        id0x17ECountCH2++;

                        if (id0x17ECountCH2 > 255)
                        {
                            id0x17ECountCH2 = 0;
                        }
                    }
                }
                if (counter % 10 == 0)
                {
                    canFd.SendMessage(0x3BB, id0x3BBMessage, 1);
                }
                if (isStrongMode)
                {
                    if (counter % 20 == 0)
                    {
                        canFd.SendMessage(0x63E, "02 3E 00 00 00 00 00 00", 1);
                    }
                }
            }
            counter++;
        }

        /// <summary>
        /// 停止后台线程
        /// </summary>
        public void ExitStrongControlMode()
        {
            isStrongMode = false;
            canFd.SendMessage(0x63E, "04 2F 10 A7 00 00 00 00", 0);
            canFd.SendMessage(0x63E, "04 2F 10 A7 00 00 00 00", 1);
        }

        public void StopCharging()
        {
            isChargingCH1 = false;
            isChargingCH2 = false;
            counter = 0;
        }

        /// <summary>
        /// 启动charging动画
        /// </summary>
        public void StartCharging()
        {
            counter = 0;
            isChargingCH1 = true;
            isChargingCH2 = true;
        }

        /// <summary>
        /// 强控模式
        /// </summary>
        /// <param name="mode">
        /// 1 奇数行扫描
        /// 2 偶数行扫描
        /// 3 奇数列扫描
        /// 4 偶数列扫描
        /// 5 80%全量工况
        /// </param>
        public void SetStrongControlMode(int mode)
        {
            // 实现代码
            isChargingCH1 = true;
            canFd.SendMessage(0x63E, "02 10 03 00 00 00 00 00", 0);
            Thread.Sleep(100);
            canFd.SendMessage(0x63E, "02 3E 00 00 00 00 00 00", 0);
            Thread.Sleep(100);
            canFd.SendMessage(0x63E, $"06 2F 10 A7 03 0{mode} 00 00", 0);
            Thread.Sleep(100);

            isChargingCH2 = true;
            canFd.SendMessage(0x63E, "02 10 03 00 00 00 00 00", 1);
            Thread.Sleep(100);
            canFd.SendMessage(0x63E, "02 3E 00 00 00 00 00 00", 1);
            Thread.Sleep(100);
            canFd.SendMessage(0x63E, $"06 2F 10 A7 03 0{mode} 00 00", 1);
            Thread.Sleep(100);

            isStrongMode = true;
        }

        /// <summary>
        /// 检测0x3FD报文周期
        /// </summary>
        public bool Check0x3FDMessageCycle(int ch = 0)
        {
            // 实现代码
            canFd.ClearBuffer(ch);
            Thread.Sleep(1000);
            var data0x3FD = canFd.FindDataByID(0x3FD, ch);
            if (data0x3FD.Count == 0)
            {
                return false;
            }
            for (int i = 1; i < data0x3FD.Count; i++)
            {
                var lastTimeStamp = data0x3FD[i - 1].TimeStamp;
                var currentTimeStamp = data0x3FD[i].TimeStamp;

                int timeDiff = (int)(currentTimeStamp - lastTimeStamp) / 1000;//ms
                Console.WriteLine(timeDiff);
                if (Math.Abs(timeDiff - 100) > 10)
                {
                    return false;
                }
            }
            return true;
        }

        private byte[] SendMessageWaitResponse(uint sendId, byte[] message, uint respId, int ch = 0)
        {
            canFd.ClearBuffer(ch);
            canFd.SendMessage(sendId, message, ch);
            Stopwatch sw = Stopwatch.StartNew();
            List<CanFdData> datas;
            while ((datas = canFd.FindDataByID(respId, ch)).Count == 0)
            {
                if (sw.ElapsedMilliseconds > 1000)
                {
                    throw new Exception($"通道[{ch + 1}]canfd wait response timeout");
                }
                Thread.Sleep(10);
            }
            return datas[0].Data;
        }

        /// <summary>
        /// 读取Boot版本号
        /// </summary>
        public string readBootVersion(int ch = 0)
        {
            // 实现代码
            var resp = SendMessageWaitResponse(0x63E, new byte[] { 03, 0x22, 0xF1, 0x80, 0, 0, 0, 0 }, 0x6BE, ch);
            return ASCIIEncoding.ASCII.GetString(resp.Skip(5).Take(17).ToArray());
        }

        /// <summary>
        /// 读取App版本号
        /// </summary>
        public string readAppVersion(int ch = 0)
        {
            // 实现代码
            var resp = SendMessageWaitResponse(0x63E, new byte[] { 03, 0x22, 0xF1, 0x81, 0, 0, 0, 0 }, 0x6BE, ch);
            return ASCIIEncoding.ASCII.GetString(resp.Skip(5).Take(17).ToArray());
        }

        /// <summary>
        /// 读取硬件版本号
        /// </summary>
        public string readHardwareVersion(int ch = 0)
        {
            // 实现代码
            var resp = SendMessageWaitResponse(0x63E, new byte[] { 03, 0x22, 0xF1, 0x7F, 0, 0, 0, 0 }, 0x6BE, ch);
            return ASCIIEncoding.ASCII.GetString(resp.Skip(5).Take(17).ToArray());
        }

        /// <summary>
        /// 读取软件版本号
        /// </summary>
        public string readSoftwareVersion(int ch = 0)
        {
            // 实现代码
            var resp = SendMessageWaitResponse(0x63E, new byte[] { 03, 0x22, 0xF1, 0x89, 0, 0, 0, 0 }, 0x6BE, ch = 0);
            return ASCIIEncoding.ASCII.GetString(resp.Skip(5).Take(17).ToArray());
        }

        /// <summary>
        /// 读取零件号
        /// </summary>
        public string readPartNumber(int ch = 0)
        {
            // 实现代码
            var resp = SendMessageWaitResponse(0x63E, new byte[] { 03, 0x22, 0xF1, 0x87, 0, 0, 0, 0 }, 0x6BE, ch);
            return ASCIIEncoding.ASCII.GetString(resp.Skip(5).Take(14).ToArray());
        }

        /// <summary>
        /// 读取素材版本号
        /// </summary>
        public string readMaterialVersion(int ch = 0)
        {
            // 实现代码
            var resp = SendMessageWaitResponse(0x63E, new byte[] { 03, 0x22, 0x10, 0x4C, 0, 0, 0, 0 }, 0x6BE, ch);
            return ASCIIEncoding.ASCII.GetString(resp.Skip(4).Take(4).ToArray());
        }

        /// <summary>
        /// 读取工厂模式
        /// </summary>
        public bool verifyFactoryMode(int ch)
        {
            // 实现代码
            var resp = SendMessageWaitResponse(0x63E, new byte[] { 03, 0x22, 0x01, 0x10, 0, 0, 0, 0 }, 0x6BE, ch);
            return resp[4] == 0xff;
        }

        /// <summary>
        /// Flash文件校验
        /// </summary>
        public bool verifyFlashFile(int ch = 0)
        {
            canFd.ClearBuffer(0);
            canFd.ClearBuffer(1);
            // 实现代码
            var resp = SendMessageWaitResponse(0x63E, new byte[] { 02, 0x10, 0x03, 0, 0, 0, 0, 0 }, 0x6BE, ch);

            resp = SendMessageWaitResponse(0x63E, new byte[] { 04, 0x31, 0x01, 0xFE, 0xFF, 0, 0, 0 }, 0x6BE, ch);

            bool isTimeout = false;
            Task.Run(() =>
            {
                Thread.Sleep(30000);
                isTimeout = true;
            });

            int errTimes = 0;
            while (true)
            {
                if (isTimeout)
                {
                    return false;
                }

                try
                {
                    resp = SendMessageWaitResponse(0x63E, new byte[] { 04, 0x31, 0x03, 0xFE, 0xFF, 0, 0, 0 }, 0x6BE, ch);
                }
                catch (Exception ex)
                {
                    Mylog.Error(ex.Message);
                    errTimes++;
                }

                if (errTimes > 3)
                {
                    throw new Exception("连续3次未返回[6BE]数据");
                }

                int activePartitionChecksumResult = resp[5];
                int backupPartitionChecksumResult = resp[6];
                Thread.Sleep(100);
                if (activePartitionChecksumResult == 2 || backupPartitionChecksumResult == 2)
                {
                    continue;
                }
                else if (activePartitionChecksumResult == 0 && backupPartitionChecksumResult == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// 系统电压读取
        /// </summary>
        public double readSystemVoltage(int ch = 0)
        {
            // 实现代码
            var resp = SendMessageWaitResponse(0x63E, new byte[] { 03, 0x22, 0x10, 0x00, 0, 0, 0, 0 }, 0x6BE, ch);
            return resp[4] / 10.0;
        }

        /// <summary>
        /// 故障DTC读取
        /// </summary>
        public bool verifyReadDTC(int ch = 0)
        {
            // 实现代码
            var resp = SendMessageWaitResponse(0x63E, new byte[] { 03, 0x19, 0x02, 0x01, 0, 0, 0, 0 }, 0x6BE, ch);
            var okResp = new byte[] { 0x59, 0x02, 0x0B };
            return resp.Skip(1).Take(3).ToArray().SequenceEqual(okResp);
        }

        /// <summary>
        /// 故障DTC清除
        /// </summary>
        public bool checkClearDTC(int ch = 0)
        {
            // 实现代码
            byte[] passResp = new byte[] { 0x01, 0x54 };
            canFd.ClearBuffer(ch);
            canFd.SendMessage(0x63E, new byte[] { 04, 0x14, 0xFF, 0xFF, 0xFF, 0, 0, 0 }, ch);
            for (int i = 0; i < 10; i++)
            {
                var resp = canFd.FindDataByID(0x6BE, ch);
                if (resp.Count > 0)
                {
                    foreach (var item in resp)
                    {
                        if (item.Data.Take(2).ToArray().SequenceEqual(passResp))
                            return true;
                    }
                }
                Thread.Sleep(1000);
            }
            return false;
        }

        public void Close()
        {
            if (isInit)
            {
                isInit = false;
                Thread.Sleep(500);
                canFd.CloseDevice();
            }
        }
    }
}